package co.fitstart.admin.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.BusinessException;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dynamic;
import com.demo2do.core.support.Page;
import com.demo2do.core.utils.CollectionUtils;
import com.demo2do.core.utils.DateFormatUtils;
import com.demo2do.core.utils.DateUtils;

import co.fitstart.admin.dao.CourseRoundDao;
import co.fitstart.admin.dao.CourseScheduleDao;
import co.fitstart.admin.dao.ReportDao;
import co.fitstart.admin.entity.content.RoundSearch;
import co.fitstart.admin.handler.TencentHandler;
import co.fitstart.admin.service.OfflineRoundService;
import co.fitstart.entity.Constant;
import co.fitstart.entity.coach.CoachStudentRelation;
import co.fitstart.entity.course.Course;
import co.fitstart.entity.course.CourseType;
import co.fitstart.entity.course.round.CourseRound;
import co.fitstart.entity.course.round.GroupRoundAttr;
import co.fitstart.entity.course.round.RoundStatus;
import co.fitstart.entity.course.schedule.CourseSchedule;
import co.fitstart.entity.course.schedule.ScheduleStatus;
import co.fitstart.entity.order.Order;
import co.fitstart.entity.order.OrderAttribute;
import co.fitstart.entity.order.OrderStatus;
import co.fitstart.entity.order.PaymentStatus;
import co.fitstart.entity.principal.Principal;
import co.fitstart.entity.principal.PrincipalMessage;
import co.fitstart.entity.report.RevenueReport;
import co.fitstart.entity.site.Site;
import co.fitstart.entity.user.bwh.BwhRecord;

/**
 * 
 * @author lidan
 *
 */
@Service("offlineRoundService")
public class OfflineRoundServiceImpl implements OfflineRoundService{
    
    @Dynamic
    private CourseRoundDao courseRoundDao;
    
    @Dynamic
    private CourseScheduleDao courseScheduleDao;
    
    @Dynamic
    private ReportDao reportDao;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    @Autowired
    private TencentHandler tencentHandler;
    
    private static final Logger logger = LoggerFactory.getLogger(OfflineRoundServiceImpl.class);
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#listGroupRound(co.fitstart.entity.site.Site, java.lang.String, co.fitstart.entity.course.CourseType, com.demo2do.core.support.Page)
     */
    public List<CourseRound> listGroupRound(Site site, String status, CourseType courseType, Page page) {
        
        List<CourseRound> result = new ArrayList<CourseRound>();
        
        if(site == null) {
            if(status.equalsIgnoreCase("arranging")) {
                result = courseRoundDao.listArrangingGroupRound(courseType, page.getBeginIndex(), page.getMaxResultRecords());
            } else {
                result = courseRoundDao.listGroupRound(courseType, RoundStatus.aliasOf(status), page.getBeginIndex(), page.getMaxResultRecords());
            }
            
        } else {
            if(status.equalsIgnoreCase("arranging")) {
                result = courseRoundDao.listArrangingGroupRound(site, courseType, page.getBeginIndex(), page.getMaxResultRecords());
            } else {
                result = courseRoundDao.listGroupRound(site, courseType, RoundStatus.aliasOf(status), page.getBeginIndex(), page.getMaxResultRecords());
            }
        }
        
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.OfflineRoundService#listGroupRound(java.util.List, java.lang.String, co.fitstart.entity.course.CourseType, com.demo2do.core.support.Page)
     */
    public List<CourseRound> listGroupRound(List<Site> sites, String status, CourseType courseType, Page page) {
        List<CourseRound> result = new ArrayList<CourseRound>();
        
        if(status.equalsIgnoreCase("arranging")) {
            result = courseRoundDao.listArrangingGroupRound(sites, courseType, page.getBeginIndex(), page.getMaxResultRecords());
        } else {
            result = courseRoundDao.listGroupRound(sites, courseType, RoundStatus.aliasOf(status), page.getBeginIndex(), page.getMaxResultRecords());
        }
        
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.OfflineRoundService#listCourseRound(co.fitstart.entity.course.CourseType, co.fitstart.entity.course.Course)
     */
    public List<Map<String, Object>> listCourseRound(CourseType courseType, Course course) {
        return courseRoundDao.listRoundByCourse(courseType, course);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.OfflineRoundService#listCourseRound(co.fitstart.entity.course.CourseType, co.fitstart.entity.course.Course, java.util.List)
     */
    public List<Map<String, Object>> listCourseRound(CourseType courseType, Course course, List<Site> sites) {
        return courseRoundDao.listRoundByCourse(courseType, course, sites);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#listCourseRound(java.util.List)
     */
    public List<CourseRound> listCourseRound(List<Long> courseRoundIds) {
        return courseRoundDao.listCourseRound(courseRoundIds);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#listCourseRound(java.lang.String)
     */
    public List<CourseRound> listCourseRound(String code) {
        List<RoundStatus> roundStatus = new ArrayList<RoundStatus>();
        roundStatus.add(RoundStatus.PREPARE);
        roundStatus.add(RoundStatus.HOLD);
        roundStatus.add(RoundStatus.READY);
        
        return courseRoundDao.listCourseRound(code, roundStatus);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#listCourseRound(co.fitstart.entity.course.Course, co.fitstart.entity.course.round.RoundStatus)
     */
    public List<CourseRound> listCourseRound(Course course, RoundStatus roundStatus) {
        return courseRoundDao.listCourseRound(course, roundStatus);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#listCourseRound(co.fitstart.entity.course.CourseType)
     */
    public List<CourseRound> listCourseRound(CourseType courseType) {
        return courseRoundDao.listGroupRound(courseType);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#search(co.fitstart.admin.entity.content.RoundSearch, com.demo2do.core.support.Page)
     */
    @SuppressWarnings("unchecked")
    public List<CourseRound> search(RoundSearch roundSearch, Page page) {
        if("1".equals(roundSearch.getDishonesty()) || "0".equals(roundSearch.getDishonesty())) {
            List<CourseRound> dishonestyRound = courseRoundDao.listDishonestyRound("1");
            
            if(dishonestyRound != null && dishonestyRound.size() > 0) {
                roundSearch.setDishonestyRound(dishonestyRound);
            } else {
                if("1".equals(roundSearch.getDishonesty())) {
                    return null;
                } else {
                    roundSearch.setDishonestyRound(null);
                }
            }
        }
        
        List<CourseRound> result = genericDaoSupport.searchForList(roundSearch.buildSentenceTemplate(), roundSearch.buildParameters(), page.getBeginIndex(), page.getMaxResultRecords());
        
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#loadCourseRound(java.lang.String)
     */
    public CourseRound loadCourseRound(String code) {
        return courseRoundDao.loadCourseRound(code);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#editHours(co.fitstart.entity.course.round.CourseRound, int)
     */
    public void editHours(CourseRound courseRound, int hours) {
        int oldHours = Integer.parseInt(courseRound.getAttrs().get(Constant.COURSE_AMOUNT).getValue());
        logger.trace("editHour - courseRound [{}] before edit courseAmount is [{}]", courseRound.getId(), oldHours);
        
        if(courseRound.getCourseStatus().isPrepare() || courseRound.getCourseStatus().isReady()) {
            genericDaoSupport.update(courseRound.editAttribute(Constant.COURSE_AMOUNT, hours));
            
            if(courseRound.getCourseStatus().isReady() || courseRound.getCoach() != null) {
                if(oldHours < hours) {
                    for(int i = 0; i < (hours - oldHours); i++ ) {
                        CourseSchedule courseSchedule = new CourseSchedule(courseRound, ScheduleStatus.SCHEDULE);
                        genericDaoSupport.save(courseSchedule);
                    }
                } else if(oldHours > hours) {
                    int count = courseScheduleDao.count(courseRound, ScheduleStatus.SCHEDULE);
                    if(count < (oldHours-hours)) {
                        throw new BusinessException("不可修改课时");
                    } else {
                        List<CourseSchedule> scheduleList = courseScheduleDao.listCourseSchedule(courseRound, ScheduleStatus.SCHEDULE, 0, oldHours-hours);
                        for(CourseSchedule courseSchedule : scheduleList) {
                            courseSchedule.disabled();
                        }
                    }
                }
                
            }
        }
        logger.trace("editHour - courseRound [{}] after edit courseAmount is [{}]", courseRound.getId(), courseRound.getAttrs().get(Constant.COURSE_AMOUNT).getValue());
    }
    

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#bindIndividualCourseCoach(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.principal.Principal)
     */
    public void bindIndividualCourseCoach(CourseRound courseRound, Principal coach) {
        
        if(!courseRound.getSchedules().isEmpty()) {
            throw new BusinessException("您已绑定教练,请不要重复绑定");
        } else if(courseRound.getOrder().getSalesman() == null && !courseRound.getCourse().isExperience()) {
            throw new BusinessException("未指定销售人员，不可指定主教练");
        }
        
        // Step1 bind course round coach
        genericDaoSupport.update(courseRound.bindCoach(coach));
        
        // Step2 create course schedule by course & courseRound
        Course course = courseRound.getCourse();
        
        int hours = course.getHours();
        
        // if hours changed
        if(!courseRound.getAttrs().isEmpty() && courseRound.getAttrs().get(Constant.COURSE_AMOUNT) != null) {
            hours = Integer.parseInt(courseRound.getAttrs().get(Constant.COURSE_AMOUNT).getValue());
        }
        
        for(int i = 0; i < hours; i++ ) {
            CourseSchedule courseSchedule = new CourseSchedule(courseRound, ScheduleStatus.SCHEDULE);
            genericDaoSupport.save(courseSchedule);
        }
        logger.trace("bindIndividualCourseCoach - courseRound [{}] save [{}] courseSchedules", courseRound.getId(), hours);
        
        String message = "您有新的学员【" + courseRound.getStudent().getName() + "】，请在我的学员点击查看，并排课";
        
        // Step3 create new principal message
        PrincipalMessage principalMessage = new PrincipalMessage(coach);
        genericDaoSupport.save(principalMessage.initialize("新学员", "您有新的学员", message));
        
        // Step4 send tencent message to coach
        tencentHandler.sendMessage(message, coach.getMobile());
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#changeIndividualCourseCoach(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.principal.Principal)
     */
    public void changeIndividualCourseCoach(CourseRound courseRound, Principal coach) {
        // Step1 bind course round coach
        genericDaoSupport.update(courseRound.bindCoach(coach));
        
        PrincipalMessage principalMessage = new PrincipalMessage(coach);
        
        if(courseRound.getCourseStatus().isReady()) {
            genericDaoSupport.save(principalMessage.initialize("转教练学员", "您有新的转教练学员", "您有新的转教练学员【"+courseRound.getStudentName()+"】，已排课，请在我的学员点击查看"));
            
            tencentHandler.sendMessage("您有新的转教练学员【"+courseRound.getStudentName()+"】，已排课，请在我的学员点击查看", coach.getMobile());
        }else if(courseRound.getCourseStatus().isPrepare()) { 
           genericDaoSupport.save(principalMessage.initialize("转教练学员", "您有新的转教练学员【"+courseRound.getStudentName()+"】, 还未排课", "您有新的转教练学员【"+courseRound.getStudentName()+"】，暂未排课，请进入首页课件界面进行分组并完成课件"));
           
           tencentHandler.sendMessage("您有新的转教练学员【"+courseRound.getStudentName()+"】，暂未排课，请进入首页课件界面进行分组并完成课件", coach.getMobile());
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#generateGroup(java.util.List, java.lang.String, java.lang.String, java.lang.String)
     */
    public void generateGroup(List<CourseRound> courseRounds, String courseCode, String gym, String startDate) {
        
        Date currentDate = new Date();
        
        for(CourseRound courseRound : courseRounds) {
            
            genericDaoSupport.update(courseRound.group(currentDate, courseCode, gym, startDate));
            
            Course course = courseRound.getCourse();
            
            for(int i = 0; i< course.getHours(); i++) {
                CourseSchedule courseSchedule = new CourseSchedule(courseRound, ScheduleStatus.SCHEDULE);
                genericDaoSupport.save(courseSchedule);
            }
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#arrangeGroup(java.util.List, java.util.Date, java.lang.String[])
     */
    public void arrangeGroup(List<CourseRound> courseRounds, Date beginDate, String... dayhour) {
        // Step1 load all courseSchedule by courseRounds
        List<CourseSchedule> courseSchedules = courseScheduleDao.listCourseSchedule(courseRounds, ScheduleStatus.SCHEDULE);
        Map<String, List<CourseSchedule>> courseScheduleMap = CollectionUtils.constructMapValuesFromList(courseSchedules, "courseRound.id");
        
        // Step2 calculate dayhours
        List<String> dayhours = this.calculateDayhour(courseRounds.get(0).getCourse(), beginDate, dayhour);
        
        // validate data
        if(dayhours.size() != courseRounds.get(0).getCourse().getHours()) {
            throw new BusinessException("排课参数错误");
        }
        
        // Step3 update schedule to schedule status
        for(String key : courseScheduleMap.keySet()) {
            
            for(int i = 0; i < dayhours.size(); i++) {
                
                String[] currentDayhour = StringUtils.split(dayhours.get(i), '|');
                
                Date currentDateTime = DateUtils.parseDate(currentDayhour[0] + " " + currentDayhour[1] + ":00", "yyyy-MM-dd HH:mm:SS");
                
                if(currentDateTime.before(new Date())) {
                    throw new BusinessException("所选时间小于当前时间，请重新选择");
                }
                
                CourseSchedule courseSchedule = courseScheduleMap.get(key).get(i);
                genericDaoSupport.update(courseSchedule.arrange(currentDayhour[0], currentDayhour[1]));
                
            }
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.ecommerce.CourseRoundService#calculateDayhour(co.fitstart.common.entity.course.Course, java.util.Date, java.util.List)
     */
    public List<String> calculateDayhour(Course course, Date beginDate, String ... dayhours) {
        
        List<String> result = new ArrayList<String>();
        
        // prepare monday and offset weeks
        Date monday = DateUtils.getFirstWeekDay(beginDate);
        int weeks = course.getWeeks();
        
        if(ArrayUtils.isNotEmpty(dayhours)) {
            
            for(String daySlashHour : dayhours) { // for selected dayhours
                
                String[] dayhour = StringUtils.split(daySlashHour, "|");
                int offset = Integer.valueOf(dayhour[0]);
                
                // calculate first day
                Date first = DateUtils.addDays(monday, offset);
                
                // init index & weeks
                int index = first.before(beginDate) ? 1 : 0;
                int tempWeeks = first.before(beginDate) ? weeks + 1 : weeks;
                
                for(int i = index; i < tempWeeks; i++) { // for every weeks
                    
                    Date base = DateUtils.addWeeks(monday, i); // calculate base first
                    Date day = DateUtils.addDays(base, offset); // calculate selected day of every week
                    
                    result.add(DateFormatUtils.format(day, "yyyy-MM-dd") + "|" + dayhour[1]);
                }
            }
            
        }
        
        return result;
        
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#editGroupBasic(java.lang.String, co.fitstart.entity.course.round.GroupRoundAttr)
     */
    public void editGroupBasic(String roundCode, GroupRoundAttr groupRoundAttr) {
        List<CourseRound> courseRounds = this.listCourseRound(roundCode);
        
        for(CourseRound courseRound : courseRounds) {
            
            genericDaoSupport.update(courseRound.editGroupBasic(groupRoundAttr));
            
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#bindGroupRoundCoach(co.fitstart.entity.principal.Principal, java.lang.String, java.lang.String)
     */
    public void bindGroupRoundCoach(Principal coach, String roundCode, String dayhour) {
        // Step1 list course round by code
        List<CourseRound> courseRounds = this.listCourseRound(roundCode);
        
        // Step2 list course schedule by courseRound & dayhour
        List<ScheduleStatus> status = new ArrayList<ScheduleStatus>();
        status.add(ScheduleStatus.SCHEDULE);
        status.add(ScheduleStatus.READY);
        
        String[] dayhours = StringUtils.split(dayhour, "|");
        
        List<CourseSchedule> courseSchedules = courseScheduleDao.listCourseSchedule(courseRounds, status, DateUtils.toDate(dayhours[0]), dayhours[1]);
        
        // Step3 第一次还没绑定教练的时候改变courseRound and order 的状态，之后已经都绑定过教练的就不用改了
        for (CourseRound courseRound : courseRounds) {
            
            if (courseRound.getCoach() == null) {
                
                genericDaoSupport.update(courseRound.readyCourse().initPeriod(null));
                
                // update order status to processing
                if(MapUtils.isNotEmpty(courseRound.getAttrs()) && courseRound.getAttrs().get(co.fitstart.entity.Constant.COURSER_ROUND_ORDER) != null) {
                    
                    Long orderId = Long.parseLong(courseRound.getAttrs().get(co.fitstart.entity.Constant.COURSER_ROUND_ORDER).getValue());
                    Order order = genericDaoSupport.load(Order.class, orderId);
                    
                    order.orderStatus(OrderStatus.PROCESSING);
                    genericDaoSupport.update(order);
                }
            }
        }
        
        // Step4 update course schedule & course round
        for(CourseSchedule courseSchedule : courseSchedules) {
            
            // bind course schedule course & update status
            genericDaoSupport.update(courseSchedule.bindCoach(coach));
            
            // bind course round coach
            CourseRound courseRound = courseSchedule.getCourseRound();
            genericDaoSupport.update(courseRound.bindGroupCoach(coach));
            
            // save or update coachStudentRelation
            CoachStudentRelation coachStudentRelation = courseScheduleDao.loadCoachStudentRelation(CourseType.GROUP, coach, courseRound.getStudent());
            if(coachStudentRelation == null) {
                coachStudentRelation = new CoachStudentRelation(coach, courseSchedule);
            }
            genericDaoSupport.saveOrUpdate(coachStudentRelation.editSchedule(courseSchedule));
        }
        
        // Step5 create new principal message
        PrincipalMessage principalMessage = new PrincipalMessage(coach);
        genericDaoSupport.save(principalMessage.initialize("新团课课程", "您有新的团课学员课程", "您有新的团课学员，请在我的学员点击您具体情况。"));
        
        // TODO Step6 send message
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#addGroupRound(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void addGroupRound(CourseRound courseRound, String roundCode) {
        CourseRound groupRound = this.loadCourseRound(roundCode);
        
        // 1. 改变newRound字段
        genericDaoSupport.update(courseRound.syncRound(groupRound));
        
        // 2. 根据originalRound，新建courseSchedule多条记录
        List<CourseSchedule> schedules = groupRound.getSchedules();
        
        for(CourseSchedule groupSchedule : schedules) {
            CourseSchedule courseSchedule = new CourseSchedule(courseRound, groupSchedule);
            genericDaoSupport.save(courseSchedule);
        }
        
        // 3. 只有courseRound的状态是ready的时候需要改变订单状态
        if (courseRound.getCourseStatus().isReady()) {
            
            if(MapUtils.isNotEmpty(courseRound.getAttrs()) && courseRound.getAttrs().get(co.fitstart.entity.Constant.COURSER_ROUND_ORDER) != null) {
                
                Long orderId = Long.parseLong(courseRound.getAttrs().get(co.fitstart.entity.Constant.COURSER_ROUND_ORDER).getValue());
                
                Order order = genericDaoSupport.load(Order.class, orderId);
                order.orderStatus(OrderStatus.PROCESSING);
                genericDaoSupport.update(order);
            }
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.OfflineRoundService#dropCourse(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.order.Order)
     */
    public void dropCourse(CourseRound courseRound, Boolean isRefund, BigDecimal refundPrice) {
        // 1. 找出不是finish状态的CourseSchedule,然后disable它们
        List<CourseSchedule> schedules = courseRound.getSchedules();
        
        for (CourseSchedule courseSchedule : schedules) {
            if (!courseSchedule.getScheduleStatus().isFinish()) {
                genericDaoSupport.update(courseSchedule.disabled());
            }
        }
        
        // 2. 改变courseRound的状态
        genericDaoSupport.update(courseRound.changeStatus(RoundStatus.FINISH));
        
        // 3. update order status to canceled and order's paymentStatus to systemrefunded
        if(MapUtils.isNotEmpty(courseRound.getAttrs()) && courseRound.getAttrs().get(co.fitstart.entity.Constant.COURSER_ROUND_ORDER) != null) {
            
            Long orderId = Long.parseLong(courseRound.getAttrs().get(co.fitstart.entity.Constant.COURSER_ROUND_ORDER).getValue());
            Order order = genericDaoSupport.load(Order.class, orderId);
            
            if(isRefund) {
                order.orderStatus(OrderStatus.CANCELED);
                order.paymentStatus(PaymentStatus.REFUNDED);
                order.editRefundPrice(refundPrice);
                
                // delete purchase report if exist
                RevenueReport revenueReport = reportDao.loadRevenueReport(courseRound);
                if(revenueReport != null) {
                    genericDaoSupport.update(revenueReport.disable());
                }
                
                OrderAttribute orderAttribute = new OrderAttribute(order, "refund_time", DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
                genericDaoSupport.save(orderAttribute);
                
            } else {
                order.orderStatus(OrderStatus.COMPLETE);
            }
            
            genericDaoSupport.update(order);
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.course.OfflineRoundService#transfer(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void transfer(CourseRound courseRound, String roundCode) {
        CourseRound targetRound = loadCourseRound(roundCode);
        
        // 1. 找出不是finish状态的CourseSchedule,然后disable它们
        List<CourseSchedule> schedules = courseRound.getSchedules();
        
        for (CourseSchedule courseSchedule : schedules) {
            if (!courseSchedule.getScheduleStatus().isFinish()) {
                genericDaoSupport.update(courseSchedule.disabled());
            }
        }
        
        // 2. 改变courseRound的状态并disable
        courseRound.changeStatus(RoundStatus.FINISH)
                   .disabled();
        
        genericDaoSupport.update(courseRound);
        
        // 3. 新建一个courseRound
        //FIXME
        //CourseRound transferRound = new CourseRound(null, courseRound.getStudent(), targetRound.getCourse(), targetRound.getSite(), targetRound.getProduct());
        
        // 4. 根据旧courseRound属性，绑定订单, 并修改订单状态
        if(MapUtils.isNotEmpty(courseRound.getAttrs()) && courseRound.getAttrs().get(co.fitstart.entity.Constant.COURSER_ROUND_ORDER) != null) {
            
            // 绑定订单
            Long orderId = Long.parseLong(courseRound.getAttrs().get(co.fitstart.entity.Constant.COURSER_ROUND_ORDER).getValue());
            //transferRound.addAttribute(co.fitstart.entity.Constant.COURSER_ROUND_ORDER, orderId.toString());
            
            // 修改订单状态
            if(targetRound.getCourseStatus().isReady()) {
                Order order = genericDaoSupport.load(Order.class, orderId);
                order.orderStatus(OrderStatus.PROCESSING);
                genericDaoSupport.update(order);
            }
        }
        
        // 5. 根据选择的所要转的团，同步
        //genericDaoSupport.save(transferRound.syncRound(targetRound));
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.OfflineRoundService#removeCourse(co.fitstart.entity.course.round.CourseRound)
     */
    public void removeCourse(CourseRound courseRound) {
        // change course round's status to arranging
        genericDaoSupport.update(courseRound.removeCourse());
        
        // delete course round's schedules
        List<CourseSchedule> schedules = courseRound.getSchedules();
        for(CourseSchedule courseSchedule : schedules) {
            genericDaoSupport.delete(courseSchedule);
        }
    }
        
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.YearRoundService#setYearRoundKeyCoach(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.principal.Principal)
     */
    public void setYearRoundKeyCoach(CourseRound courseRound, Principal coach){
        genericDaoSupport.update(courseRound.bindCoach(coach));
    } 
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.OfflineRoundService#addBwh(co.fitstart.entity.user.bwh.BwhRecord, co.fitstart.entity.course.round.CourseRound)
     */
    
    public void addBwh(BwhRecord bwhRecord,CourseRound courseRound, Principal principal) {
    	
    	genericDaoSupport.save(bwhRecord.initilization(courseRound, principal));
    	
    }
}
